import { BaseConnection } from "tsrpc";
import { MsgAction, template } from "./shared/master/MsgAction";
import { logger } from "./model/server/logger";
import { SKILL, SK_data } from "./model/fight/skill/SK_active";
import { enemy } from "./model/fight/body/enemy";
import SK_func from "./model/fight/skill/SK_func";
import { wordCfg } from "./model/word/word";
import { prop_base } from "./model/bag/prop_base";
import { prop_equip } from "./model/bag/prop_equip";
import { EffectType, bar, face_Points, face_prop_item, group, prop_min_type } from "./shared/interface";
import { equip } from "./model/fight/equip/equip";
import { prop_SkillBook } from "./model/bag/prop_SkillBook";
import { calls } from "./model/fight/body/calls";
import { pet } from "./model/fight/body/pet";
import { prop_PetEgg } from "./model/bag/prop_PetEgg";
import { _Cls_Points } from "./model/fight/body/att/_Points";
import { _Cls_Att } from "./model/fight/body/att/_Att";
import { CreateBody_base, baseBody } from "./model/fight/body/baseBody";
import { prop_AttBook } from "./model/bag/prop_AttBook";
import { prop_TeamCard } from "./model/bag/prop_TeamCard";
import body_tool from "./model/fight/body/body_tool";
import { npc } from "./model/fight/body/npc";
const { v4: uuidv4 } = require('uuid');
const short = require('short-uuid');
const translator = short();
export enum xlsxCfgNames {
    装备模板 = 'cfg_equipTpl',
    道具模板_普通道具 = 'prop_list',
    道具模版_属性书 = 'prop_AttBook',
    道具模版_小队邀请函 = 'prop_shareCard',
    地图配置 = 'map_cfg',
    天赋表 = 'talent',
    血统表 = 'job',
    召唤表 = 'calltable',
    /**
     * 属性价值 一级转二级属性
     */
    属性配置 = 'att_config',
    属性偏好配置 = 'cfg_att_preference',
    排行榜奖励配置 = 'cfg_rankgift',
    盲盒奖励配置 = 'cfg_BlindBox',
    捕捉宠物文案 = 'catchPetTips',
    商店配置 = 'cfg_shop',
    怪物掉落配置 = 'cfg_enemy',
    挂机配置 = 'cfg_onhook',
    签到奖励表 = 'cfg_sign',
    服务器配置 = 'cfg_server',
    委托任务表 = 'ever_entrust',
    每日任务表 = 'ever_dayTask',
    鱼库 = 'fish',
    任务_每周 = 'ever_weekTask',
    任务_新手 = 'ever_newbieTask',
    调试id = 'debugTable',
    小队表 = 'teamtable',
    基因锁表 = 'dna_name',
    名人堂 = 'neverRank'
}
class app {
    isDev: boolean = false;
    xlsxCfgMap: Map<string, Map<string, any>> = new Map();
    private attCoverMap: Map<string, number> = new Map();
    constructor() {

    }
    leveAddExp(exp: number, leve: bar, upfunc: Function) {
        leve.now += exp;
        let jude = true;
        for (let i = 0; i < 100; i++) {
            if (leve.now >= leve.max) {
                leve.now -= leve.max;
                jude = upfunc()
                if (!jude) {
                    break;
                }
            } else {
                break;
            }
        }

        if (jude && leve.now >= leve.max) {
            setTimeout(() => {
                this.leveAddExp(0, leve, upfunc)
            }, 10)
        }
    }
    isDebug(id: string) {
        return (this.xlsxCfgMap.get(xlsxCfgNames.调试id) as Map<string, any>).has(id)
    }
    /**
     * 计算属性点对象等于对应多少属性
     */
    contPToAtt(p: _Cls_Points, tag: _Cls_Att) {

        let att = new _Cls_Att();
        for (const key in p) {
            if (key.startsWith('_')) {
                continue;
            }
            if (typeof (p[key]) != 'number') {
                continue;
            }
            // 读取到属性点组成
            const cfg = (this.xlsxCfgMap.get(xlsxCfgNames.属性配置) as Map<string, any>).get(key)

            if (Object.keys(cfg.pcom).length == 0) {
                att.add({ [key]: p[key] })
            }
            for (let i = 0; i < cfg.pcom.length; i++) {
                const keys = cfg.pcom[i];
                const val = this._countPtoAtt(key, keys) * p[key]
                let obj = { [keys]: val };
                att.add(obj)
            }
        }

        return att;
    }
    getAttVaule(key: string) {
        const attCfg = this.xlsxCfgMap.get(xlsxCfgNames.属性配置) as Map<string, any>;
        const tagVaule = attCfg.get(key).value;
        return tagVaule;
    }
    BN(number: any, decimalDigit?: any) {
        if(isNaN(Number(number))){
            return number;
        }
        number = Number(number)
        decimalDigit = decimalDigit == null ? 2 : decimalDigit;
        let integer = Math.floor(number);
        let digit = this._getDigit(integer);
        // ['个', '十', '百', '千', '万', '十万', '百万', '千万']; 
        let unit: string[] = [];
        if (digit > 3) {
            let multiple = Math.floor(digit / 8);
            if (multiple >= 1) {
                let tmp = Math.round(integer / Math.pow(10, 8 * multiple));
                unit.push(this._addWan(tmp, number, 8 * multiple, decimalDigit) as any);
                for (let i = 0; i < multiple; i++) {
                    unit.push('亿');
                }
                return unit.join('');
            } else {
                return this._addWan(integer, number, 0, decimalDigit);
            }
        } else {
            return Math.ceil(number);
        }
    }
    private _addWan(integer: any, number: any, mutiple: any, decimalDigit: any) {
        let me = this;
        let digit = me._getDigit(integer);
        if (digit > 3) {
           let remainder = digit % 8;
           if (remainder >= 5) { // ‘十万’、‘百万’、‘千万’显示为‘万’ 
              remainder = 4;
           }
           return Math.round(number / Math.pow(10, remainder + mutiple - decimalDigit)) / Math.pow(10, decimalDigit) + '万';
        } else {
           return Math.round(number / Math.pow(10, mutiple - decimalDigit)) / Math.pow(10, decimalDigit);
        }
     }
     private _getDigit(integer: any) {
        let digit = -1;
        while (integer >= 1) {
           digit++;
           integer = integer / 10;
        }
        return digit;
     }
    /**
     * 计算属性点等于对应多少属性
     */
    private _countPtoAtt(p: string, tag: string): number {
        if (this.attCoverMap.has(`${p}_${tag}`)) {
            return this.attCoverMap.get(`${p}_${tag}`) as number
        }
        const attCfg = this.xlsxCfgMap.get(xlsxCfgNames.属性配置) as Map<string, any>;
        const tagVaule = attCfg.get(tag).value;
        const pCfg = attCfg.get(p) as Map<string, any>;

        let fixNum = 1;
        let find = false;
        for (const key in pCfg) {
            if (tag == key) {
                find = true;
            }
            if (!key.includes('_')) {
                continue;
            }
            if (key != tag) {
                continue;
            }
            fixNum = pCfg[key];
            break;
        }
        if (!find) {
            return 1 / tagVaule
        }
        this.attCoverMap.set(`${p}_${tag}`, fixNum)
        return fixNum
    }
    /**
     * 范围随机 数值越大概率越小
     * @param min 
     * @param max 
     * @param bias 参数用于指定偏好值（bias），即生成的随机数在一定程度上会偏向于 bias
     * @param big 参数用于限制生成的随机数的最大值
     * @returns 
     */
    generateRandom(min, max, bias?, big?: number) {
        max += 1;
        if (max < min) {
            max = min;
        }
        if (min > max) {
            max = min;
        }
        if (!bias) {
            bias = max;
        }
        let range = max - min;
        let u = Math.random() * Math.random(); // 生成0到1之间的随机数并降低概率
        let result = min + u * range;
        let resVal = Math.floor(result);
        if (bias > max) {
            resVal = (bias / max) * resVal
        }
        if (big && resVal > big) {
            resVal = big;
        }
        return resVal;
    }
    /**
     * 深拷贝
     * @param obj 
     * @returns 
     */
    deepCopy<T>(obj: T): T {
        if (typeof obj !== 'object' || obj === null) {
            return obj;
        }
        let copy: T;
        if (Array.isArray(obj)) {
            copy = [] as any;
            for (let i = 0; i < obj.length; i++) {
                copy[i] = this.deepCopy(obj[i]);
            }
        } else {
            copy = {} as any;
            for (const key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key)) {
                    copy[key] = this.deepCopy(obj[key]);
                }
            }
        }
        return copy;
    }
    setXlsxCfg(key: string, data: Map<string, any>) {
        this.xlsxCfgMap.set(key, data);
    }
    /**
     * 判断两天是否为同一天
     * @param timestamp1 
     * @param timestamp2 
     * @returns 
     */
    isSameDay(timestamp1: number, timestamp2: number) {
        const date1 = new Date(timestamp1);
        const date2 = new Date(timestamp2);

        const day1 = date1.getDate();
        const month1 = date1.getMonth();
        const year1 = date1.getFullYear();

        const day2 = date2.getDate();
        const month2 = date2.getMonth();
        const year2 = date2.getFullYear();

        return day1 === day2 && month1 === month2 && year1 === year2;
    }

    isSameWeek(timestamp1: number, timestamp2: number) {
        const date1 = new Date(timestamp1 * 1000);
        const date2 = new Date(timestamp2 * 1000);

        const oneDay = 24 * 60 * 60 * 1000;
        const oneWeek = 7 * oneDay;

        const weekStart = (date) => {
            const diff = date.getDate() - date.getDay();
            return new Date(date.setDate(diff));
        };

        const startOfWeek1 = weekStart(date1);
        const startOfWeek2 = weekStart(date2);

        return Math.abs(Number(startOfWeek1) - Number(startOfWeek2)) < oneWeek;
    }
    randomGroupPoint(sum, length) {
        const avg = sum / length;
        let remainingSum = sum;

        const randomArray = Array.from({ length: length - 1 }, () => {
            const randomValue = Math.random() * (avg * 2); // 生成不超过平均值两倍的随机数
            const randomElement = Math.min(randomValue, remainingSum - avg); // 确保随机数不超过剩余的总和
            remainingSum -= randomElement;
            return randomElement;
        });

        randomArray.push(remainingSum); // 将剩余的总和作为最后一个元素

        this.shuffleArray(randomArray)
        return randomArray;
    }
    getCfg(key: string) {
        return this.xlsxCfgMap.get(key) as Map<string, any>
    }
    /**
     * 
     * @param id 
     * @param leve 
     * @param enemyMap 
     * @param type 1 永久召唤物 2 宠物 3 npc
     * @returns 
     */
    createUnity(id: string, leve: number, enemyMap: Map<string, any>, sore: number, type?: number) {
        let body;
        if (!type) {
            body = new enemy();
        } else if (type == 1) {
            body = new calls();
        } else if (type == 2) {
            body = new pet();
        }else if(type == 3){
            body = new npc();
            // leve = 100000;
        }
        if (leve <= 0) {
            leve = 1;
        }
        leve = Math.ceil(leve);
        let maps = enemyMap;
        if (id == '-1') {
            // id = this
            const arry = [...maps.keys()];
            const idx = this.random(0, arry.length - 1);
            id = arry[idx];
        }
        let cfg = maps.get(id);

        body.setCreateCfg(cfg);

        let skills: SK_data[] = [];
        let addSkill = (name: any, rename?: string) => {
            let sk = SK_func.createSkill(name, sore)
            if (sk) {
                sk.leve.num = Math.ceil(this.random(leve * 0.8, leve * 1.2))
                if (rename) {
                    sk.rename = rename
                }
                skills.push(sk)
            }
        }
        let skillArry = (cfg.skills as string).split(',');
        for (let i = 0; i < skillArry.length; i++) {
            const skName = skillArry[i];
            const rename = skName.split('-')
            if (rename.length == 1) {
                addSkill(skName);
            } else {
                addSkill(rename[0], rename[1]);
            }
        }
        let Talent_leve = this.generateRandom(1, leve / 4);
        let Job_leve = this.generateRandom(1, leve / 4);
        if(body instanceof enemy){
            Talent_leve = this.generateRandom(1, leve / 4 +  leve % 50);
            Job_leve = this.generateRandom(1, leve / 4 +  leve % 50);
        }
        let createCfg: CreateBody_base = {
            leve: leve || 1,
            Job: '1',
            style_id: cfg.style_id || 'none',
            Job_leve: Job_leve,
            Talent: '1',
            Talent_leve: Talent_leve,
            name: cfg.name,
            Points: cfg,
            sk_actives: skills
        }
        for (const key in cfg) {
            if (typeof (createCfg[key]) == 'undefined') {
                createCfg[key] = cfg[key]
            }
        }
        body.set_Cfg(createCfg);
        body.init();


        body.res_life({
            val: -1,
            use_uuid: "",
            use_name: "",
            sk_name: "",
            group: group.主场,
            type: EffectType.buff_提升物理吸血
        })
        body_tool.add_mp(body, {
            use_uuid: "0",
            use_name: "主神空间",
            sk_name: "清晰头脑",
            group: group.客场,
            type: EffectType.none,
            val: body._attributes.Mp_Max
        })
        logger.debug('创建单位', body);
        return body;
    }
    /**
     * 权重计算
     */
    randomWeight(arry: any[]) {
        let weights: number[] = [];
        if (typeof (arry[0]) == 'number') {
            weights = arry;
        } else if (typeof (arry[0].weight) == 'number') {
            for (let i = 0; i < arry.length; i++) {
                const element = arry[i];
                weights.push(element.weight)
            }
        } else {
            return this.random(0, arry.length - 1)

        }
        let totalWeight = weights.reduce((accumulator, currentValue) => accumulator + currentValue); //计算所有权重之和
        let randomNumber = Math.random() * totalWeight; //生成0到totalWeight范围内的随机数
        let randomIdx = 0;
        for (let i = 0; i < weights.length; i++) {
            if (randomNumber <= weights[i]) {
                randomIdx = i;
                break;
            } else {
                randomNumber -= weights[i]; //更新随机数位置
            }
        }
        return randomIdx;
    }
    getCfgData(cfg_id: string) {
        let cfg;
        if (cfg_id.includes('equip')) {
            cfg = this.xlsxCfgMap.get(xlsxCfgNames.装备模板);
        } else if (cfg_id.includes('prop')) {
            cfg = this.xlsxCfgMap.get(xlsxCfgNames.道具模板_普通道具);
        }
        let data = cfg.get(cfg_id);
        return data;
    }
    getCfgPropTypeName(cfg_id: string) {
        let name = '未知';
        try {
            if (cfg_id.includes('equip')) {
                name = '⚔️装备'
            } else if (cfg_id.includes('skill')) {
                name = '📘技能书'
            } else if (cfg_id.includes('pet')) {
                name = '🥚宠物蛋'
            } else if (cfg_id.includes('att')) {
                name = '📕属性书'
            } else if (cfg_id.includes('team')) {
                name = '☮邀请函'
            } else {
                const cfg = this.xlsxCfgMap.get(xlsxCfgNames.道具模板_普通道具) as Map<string, any>;
                const item = cfg.get(cfg_id)
                if (item) {
                    name = `📦${item.name}`;
                }
            }
            if (name == '未知') {
                debugger;
            }
        } catch (error) {
            debugger
        }
        return name;
    }
    /**
     * 
     * @param cfg_id 道具ID
     * @param score 
     * @param from 
     * @returns 
     */
    createCfgItem(cfg_id: string, score: number, from: string, more?) {
        let min_type = prop_min_type.装备;
        let cfg;

        let data: face_prop_item = {
            min_type: prop_min_type.宠物蛋,
            score: score,
            from: from,
            num: 1,
            icon: undefined,
            data: undefined
        }
        if (cfg_id.includes('equip')) {
            min_type = prop_min_type.装备;
            let temp_equip = new equip();
            data.data = temp_equip;
            temp_equip.create_cfg(cfg_id, score, from);
            data.icon = temp_equip.icon;

        } else if (cfg_id.includes('prop')) {
            cfg = this.xlsxCfgMap.get(xlsxCfgNames.道具模板_普通道具);
            let cfgdata = cfg.get(cfg_id)
            data.icon = cfgdata.icon;
            min_type = prop_min_type.道具;
            data.data = cfgdata
        } else if (cfg_id.includes('skill')) {
            min_type = prop_min_type.技能书;
            let skName = cfg_id.split('-')
            let tpl = SK_func.getSkCfg_name(skName[1]) as SK_data;
            let random = false;
            if (!tpl) {
                random = true;
                const table = [...SK_func.skTplMap.values()]
                const idx = this.randomWeight(table)
                skName[1] = table[idx].name
                cfg_id = `skill_${skName[1]}`
            }
            let temp_skill = SK_func.createSkill(skName[1], score);
            if (random) {
                temp_skill.rename = '待命名技能'
            }
            data.data = temp_skill
        } else if (cfg_id.includes('pet')) {
            min_type = prop_min_type.宠物蛋;
            data.data = more;
        } else if (cfg_id.includes('att')) {
            cfg = this.xlsxCfgMap.get(xlsxCfgNames.道具模版_属性书)
            let cfgdata = cfg.get(cfg_id)
            const table = [...cfg.values()]
            if (!cfgdata) {
                // 随机
                const idx = this.randomWeight(table)
                cfgdata = table[idx]
            }
            data.icon = cfgdata.icon;
            min_type = prop_min_type.属性书;
            data.data = cfgdata
        } else if (cfg_id.includes('team')) {
            cfg = this.xlsxCfgMap.get(xlsxCfgNames.道具模版_小队邀请函)
            let cfgdata = cfg.get(cfg_id)
            min_type = prop_min_type.小队邀请函;
            data.data = cfgdata;
        }
        data.min_type = min_type;
        let item = this.createItem(data);
        if (!item.data) {
            debugger;
        }
        return item
    }
    createItem(cfg: face_prop_item): prop_base {
        let item;
        switch (cfg.min_type) {
            case prop_min_type.装备:
                item = new prop_equip(cfg);
                break;
            case prop_min_type.属性书:
                item = new prop_AttBook(cfg);
                break;
            case prop_min_type.道具:
                item = new prop_base(cfg)
                break;
            case prop_min_type.技能书:
                item = new prop_SkillBook(cfg)
                break;
            case prop_min_type.宠物蛋:
                item = new prop_PetEgg(cfg);
                break;
            case prop_min_type.小队邀请函:
                item = new prop_TeamCard(cfg);
                break;
            default:
                break;
        }
        return item;
    }
    /**
     * 读取指定地图配置
     * @param id 
     * @returns 
     */
    getWordCfg(id: string) {
        let cfgMap = this.xlsxCfgMap.get(xlsxCfgNames.地图配置) as Map<string, wordCfg>
        return cfgMap.get(id) as wordCfg
    }
    getAbsGroup(tag: group) {
        if (tag == group.主场) {
            return group.客场
        } else {
            return group.主场
        }
    }
    sendConn(conn: BaseConnection<any> | undefined, data: MsgAction) {
        if (!conn) {
            logger.debug('玩家不在线');
            return;
        }
        conn.sendMsg('Action', data);

    }
    /**
     * 打乱数组顺序
     * @param array 
     * @returns 
     */
    shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }
    v4() {
        const uuid = uuidv4();
        const id = translator.fromUUID(uuid);
        return id
    }
    /**
     * json序列化对象
     * @param obj 
     * @returns 
     */
    sanitizeObject(obj) {
        if (typeof obj !== 'object' || obj === null) {
            return obj;
        }
        if (obj.dbsave && typeof (obj.dbsave) == 'function') {
            try {
                return obj.dbsave();
            } catch (error) {
                debugger
            }
        }
        const sanitizedObj = Array.isArray(obj) ? [] : {};

        for (const prop in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                if (typeof (obj[prop]) == 'function') {
                    continue;
                }
                if (!prop.startsWith('_')) {
                    sanitizedObj[prop] = this.sanitizeObject(obj[prop]);
                }
            }
        }

        return sanitizedObj;
    }
    /**
* 获取一个随机数
*/
    random(min: number, max: number) {
        return Math.floor(Math.random() * (max - min + 1)) + min
    }
}
export default new app()